home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / gpp-1_42.lha / g++-1.42.0 / cplus-dem.c < prev    next >
C/C++ Source or Header  |  1991-10-19  |  19KB  |  966 lines

  1. /* Demangler for GNU C++ 
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.    written by James Clark (jjc@jclark.uucp)
  4.    
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 1, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* This is for g++ 1.36.1 (November 6 version). It will probably
  20.    require changes for any other version.
  21.  
  22.    Modified for g++ 1.36.2 (November 18 version).  */
  23.  
  24. /* This file exports one function
  25.  
  26.    char *cplus_demangle (const char *name)
  27.    
  28.    If `name' is a mangled function name produced by g++, then
  29.    a pointer to a malloced string giving a C++ representation
  30.    of the name will be returned; otherwise NULL will be returned.
  31.    It is the caller's responsibility to free the string which
  32.    is returned.
  33.  
  34.    For example,
  35.    
  36.    cplus_demangle ("_foo__1Ai")
  37.    
  38.    returns
  39.  
  40.    "A::foo(int)"
  41.  
  42.    This file imports xmalloc and xrealloc, which are like malloc and
  43.    realloc except that they generate a fatal error if there is no
  44.    available memory. */
  45.  
  46. /* #define nounderscore 1 /* define this is names don't start with _ */
  47.  
  48. #include <stdio.h>
  49. #include <ctype.h>
  50.  
  51. #ifdef USG
  52. #include <memory.h>
  53. #include <string.h>
  54. #else
  55. #include <strings.h>
  56. #define memcpy(s1, s2, n) bcopy ((s2), (s1), (n))
  57. #define memcmp(s1, s2, n) bcmp ((s2), (s1), (n))
  58. #define strchr index 
  59. #define strrchr rindex
  60. #endif
  61.  
  62. #ifndef __STDC__
  63. #define const
  64. #endif
  65.  
  66. #ifdef __STDC__
  67. extern char *cplus_demangle (const char *type);
  68. #else
  69. extern char *cplus_demangle ();
  70. #endif
  71.  
  72. #ifdef __STDC__
  73. extern char *xmalloc (int);
  74. extern char *xrealloc (char *, int);
  75. #else
  76. extern char *xmalloc ();
  77. extern char *xrealloc ();
  78. #endif
  79.  
  80. static char **typevec = 0;
  81. static int ntypes = 0;
  82. static int typevec_size = 0;
  83.  
  84. static struct {
  85.   const char *in;
  86.   const char *out;
  87. } optable[] = {
  88.   "new", " new",
  89.   "delete", " delete",
  90.   "ne", "!=",
  91.   "eq", "==",
  92.   "ge", ">=",
  93.   "gt", ">",
  94.   "le", "<=",
  95.   "lt", "<",
  96.   "plus", "+",
  97.   "minus", "-",
  98.   "mult", "*",
  99.   "convert", "+",    /* unary + */
  100.   "negate", "-",    /* unary - */
  101.   "trunc_mod", "%",
  102.   "trunc_div", "/",
  103.   "truth_andif", "&&",
  104.   "truth_orif", "||",
  105.   "truth_not", "!",
  106.   "postincrement", "++",
  107.   "postdecrement", "--",
  108.   "bit_ior", "|",
  109.   "bit_xor", "^",
  110.   "bit_and", "&",
  111.   "bit_not", "~",
  112.   "call", "()",
  113.   "cond", "?:",
  114.   "alshift", "<<",
  115.   "arshift", ">>",
  116.   "component", "->",
  117.   "indirect", "*",
  118.   "method_call", "->()",
  119.   "addr", "&",        /* unary & */
  120.   "array", "[]",
  121.   "nop", "",            /* for operator= */
  122. };
  123.  
  124. /* Beware: these aren't '\0' terminated. */
  125.  
  126. typedef struct {
  127.   char *b;            /* pointer to start of string */
  128.   char *p;            /* pointer after last character */
  129.   char *e;            /* pointer after end of allocated space */
  130. } string;
  131.  
  132. #ifdef __STDC__
  133. static void string_need (string *s, int n);
  134. static void string_delete (string *s);
  135. static void string_init (string *s);
  136. static void string_clear (string *s);
  137. static int string_empty (string *s);
  138. static void string_append (string *p, const char *s);
  139. static void string_appends (string *p, string *s);
  140. static void string_appendn (string *p, const char *s, int n);
  141. static void string_prepend (string *p, const char *s);
  142. #if 0
  143. static void string_prepends (string *p, string *s);
  144. #endif
  145. static void string_prependn (string *p, const char *s, int n);
  146. static int get_count (const char **type, int *count);
  147. static int do_args (const char **type, string *decl);
  148. static int do_type (const char **type, string *result);
  149. static int do_arg (const char **type, string *result);
  150. static int do_args (const char **type, string *decl);
  151. static void munge_function_name (string *name);
  152. static void remember_type (const char *type, int len);
  153. #else
  154. static void string_need ();
  155. static void string_delete ();
  156. static void string_init ();
  157. static void string_clear ();
  158. static int string_empty ();
  159. static void string_append ();
  160. static void string_appends ();
  161. static void string_appendn ();
  162. static void string_prepend ();
  163. static void string_prepends ();
  164. static void string_prependn ();
  165. static int get_count ();
  166. static int do_args ();
  167. static int do_type ();
  168. static int do_arg ();
  169. static int do_args ();
  170. static void munge_function_name ();
  171. static void remember_type ();
  172. #endif
  173.  
  174. char *
  175. cplus_demangle (type)
  176.      const char *type;
  177. {
  178.   string decl;
  179.   int n;
  180.   int success = 0;
  181.   int constructor = 0;
  182.   int const_flag = 0;
  183.   int i;
  184.   const char *p;
  185. #ifndef LONGERNAMES
  186.   const char *premangle;
  187. #endif
  188.  
  189.   if (type == NULL || *type == '\0')
  190.     return NULL;
  191. #ifndef nounderscore
  192.   if (*type++ != '_')
  193.     return NULL;
  194. #endif
  195.   p = type;
  196.   while (*p != '\0' && !(*p == '_' && p[1] == '_'))
  197.     p++;
  198.   if (*p == '\0')
  199.     {
  200.       /* destructor */
  201.       if (type[0] == '_' && type[1] == '$' && type[2] == '_')
  202.     {
  203.       int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
  204.       char *tem = (char *) xmalloc (n);
  205.       strcpy (tem, type + 3);
  206.       strcat (tem, "::~");
  207.       strcat (tem, type + 3);
  208.       strcat (tem, "()");
  209.       return tem;
  210.     }
  211.       /* static data member */
  212.       if (*type != '_' && (p = strchr (type, '$')) != NULL)
  213.     {
  214.       int n = strlen (type) + 2;
  215.       char *tem = (char *) xmalloc (n);
  216.       memcpy (tem, type, p - type);
  217.       strcpy (tem + (p - type), "::");
  218.       strcpy (tem + (p - type) + 2, p + 1);
  219.       return tem;
  220.     }
  221.       /* virtual table */
  222.       if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
  223.     {
  224.       int n = strlen (type + 4) + 14 + 1;
  225.       char *tem = (char *) xmalloc (n);
  226.       strcpy (tem, type + 4);
  227.       strcat (tem, " virtual table");
  228.       return tem;
  229.     }
  230.       return NULL;
  231.     }
  232.  
  233.   string_init (&decl);
  234.  
  235.   if (p == type)
  236.     {
  237.       if (!isdigit (p[2]))
  238.     {
  239.       string_delete (&decl);
  240.       return NULL;
  241.     }
  242.       constructor = 1;
  243.     }
  244.   else
  245.     {
  246.       string_appendn (&decl, type, p - type);
  247.       munge_function_name (&decl);
  248.     }
  249.   p += 2;
  250.  
  251. #ifndef LONGERNAMES
  252.   premangle = p;
  253. #endif
  254.   switch (*p)
  255.     {
  256.     case 'C':
  257.       /* a const member function */
  258.       if (!isdigit (p[1]))
  259.     {
  260.       string_delete (&decl);
  261.       return NULL;
  262.     }
  263.       p += 1;
  264.       const_flag = 1;
  265.       /* fall through */
  266.     case '0':
  267.     case '1':
  268.     case '2':
  269.     case '3':
  270.     case '4':
  271.     case '5':
  272.     case '6':
  273.     case '7':
  274.     case '8':
  275.     case '9':
  276.       n = 0;
  277.       do
  278.     {
  279.       n *= 10;
  280.       n += *p - '0';
  281.       p += 1;
  282.     }
  283.       while (isdigit (*p));
  284.       if (strlen (p) < n)
  285.     {
  286.       string_delete (&decl);
  287.       return NULL;
  288.     }
  289.       if (constructor)
  290.     {
  291.       string_appendn (&decl, p, n);
  292.       string_append (&decl, "::");
  293.       string_appendn (&decl, p, n);
  294.     }
  295.       else
  296.     {
  297.       string_prepend (&decl, "::");
  298.       string_prependn (&decl, p, n);
  299.     }
  300.       p += n;
  301. #ifndef LONGERNAMES
  302.       remember_type (premangle, p - premangle);
  303. #endif
  304.       success = do_args (&p, &decl);
  305.       if (const_flag)
  306.     string_append (&decl, " const");
  307.       break;
  308.     case 'F':
  309.       p += 1;
  310.       success = do_args (&p, &decl);
  311.       break;
  312.     }
  313.  
  314.   for (i = 0; i < ntypes; i++)
  315.     if (typevec[i] != NULL)
  316.       free (typevec[i]);
  317.   ntypes = 0;
  318.   if (typevec != NULL)
  319.     {
  320.       free ((char *)typevec);
  321.       typevec = NULL;
  322.       typevec_size = 0;
  323.     }
  324.  
  325.   if (success)
  326.     {
  327.       string_appendn (&decl, "", 1);
  328.       return decl.b;
  329.     }
  330.   else
  331.     {
  332.       string_delete (&decl);
  333.       return NULL;
  334.     }
  335. }
  336.  
  337. static int
  338. get_count (type, count)
  339.      const char **type;
  340.      int *count;
  341. {
  342.   if (!isdigit (**type))
  343.     return 0;
  344.   *count = **type - '0';
  345.   *type += 1;
  346.   /* see flush_repeats in cplus-method.c */
  347.   if (isdigit (**type))
  348.     {
  349.       const char *p = *type;
  350.       int n = *count;
  351.       do 
  352.     {
  353.       n *= 10;
  354.       n += *p - '0';
  355.       p += 1;
  356.     } 
  357.       while (isdigit (*p));
  358.       if (*p == '_')
  359.     {
  360.       *type = p + 1;
  361.       *count = n;
  362.     }
  363.     }
  364.   return 1;
  365. }
  366.  
  367. /* result will be initialised here; it will be freed on failure */
  368.  
  369. static int
  370. do_type (type, result)
  371.      const char **type;
  372.      string *result;
  373. {
  374.   int n;
  375.   int done;
  376.   int non_empty = 0;
  377.   int success;
  378.   string decl;
  379.   const char *remembered_type;
  380.  
  381.   string_init (&decl);
  382.   string_init (result);
  383.  
  384.   done = 0;
  385.   success = 1;
  386.   while (success && !done)
  387.     {
  388.       int member;
  389.       switch (**type)
  390.     {
  391.     case 'P':
  392.       *type += 1;
  393.       string_prepend (&decl, "*");
  394.       break;
  395.  
  396.     case 'R':
  397.       *type += 1;
  398.       string_prepend (&decl, "&");
  399.       break;
  400.  
  401.     case 'T':
  402.       *type += 1;
  403.       if (!get_count (type, &n) || n >= ntypes)
  404.         success = 0;
  405.       else
  406.         {
  407.           remembered_type = typevec[n];
  408.           type = &remembered_type;
  409.         }
  410.       break;
  411.  
  412.     case 'F':
  413.       *type += 1;
  414.       if (!string_empty (&decl) && decl.b[0] == '*')
  415.         {
  416.           string_prepend (&decl, "(");
  417.           string_append (&decl, ")");
  418.         }
  419.       if (!do_args (type, &decl) || **type != '_')
  420.         success = 0;
  421.       else
  422.         *type += 1;
  423.       break;
  424.  
  425.     case 'M':
  426.     case 'O':
  427.       {
  428.         int constp = 0;
  429.         int volatilep = 0;
  430.  
  431.         member = **type == 'M';
  432.         *type += 1;
  433.         if (!isdigit (**type))
  434.           {
  435.         success = 0;
  436.         break;
  437.           }
  438.         n = 0;
  439.         do
  440.           {
  441.         n *= 10;
  442.         n += **type - '0';
  443.         *type += 1;
  444.           } 
  445.         while (isdigit (**type));
  446.         if (strlen (*type) < n)
  447.           {
  448.         success = 0;
  449.         break;
  450.           }
  451.         string_append (&decl, ")");
  452.         string_prepend (&decl, "::");
  453.         string_prependn (&decl, *type, n);
  454.         string_prepend (&decl, "(");
  455.         *type += n;
  456.         if (member)
  457.           {
  458.         if (**type == 'C')
  459.           {
  460.             *type += 1;
  461.             constp = 1;
  462.           }
  463.         if (**type == 'V')
  464.           {
  465.             *type += 1;
  466.             volatilep = 1;
  467.           }
  468.         if (*(*type)++ != 'F')
  469.           {
  470.             success = 0;
  471.             break;
  472.           }
  473.           }
  474.         if ((member && !do_args (type, &decl)) || **type != '_')
  475.           {
  476.         success = 0;
  477.         break;
  478.           }
  479.         *type += 1;
  480.         if (constp)
  481.           {
  482.         if (non_empty)
  483.           string_append (&decl, " ");
  484.         else
  485.           non_empty = 1;
  486.         string_append (&decl, "const");
  487.           }
  488.         if (volatilep)
  489.           {
  490.         if (non_empty)
  491.           string_append (&decl, " ");
  492.         else
  493.           non_empty = 1;
  494.         string_append (&decl, "volatilep");
  495.           }
  496.         break;
  497.       }
  498.  
  499.     case 'C':
  500.       if ((*type)[1] == 'P')
  501.         {
  502.           *type += 1;
  503.           if (!string_empty (&decl))
  504.         string_prepend (&decl, " ");
  505.           string_prepend (&decl, "const");
  506.           break;
  507.         }
  508.  
  509.       /* fall through */
  510.     default:
  511.       done = 1;
  512.       break;
  513.     }
  514.     }
  515.  
  516.   done = 0;
  517.   non_empty = 0;
  518.   while (success && !done)
  519.     {
  520.       switch (**type)
  521.     {
  522.     case 'C':
  523.       *type += 1;
  524.       if (non_empty)
  525.         string_append (result, " ");
  526.       else
  527.         non_empty = 1;
  528.       string_append (result, "const");
  529.       break;
  530.     case 'U':
  531.       *type += 1;
  532.       if (non_empty)
  533.         string_append (result, " ");
  534.       else
  535.         non_empty = 1;
  536.       string_append (result, "unsigned");
  537.       break;
  538.     case 'V':
  539.       *type += 1;
  540.       if (non_empty)
  541.         string_append (result, " ");
  542.       else
  543.         non_empty = 1;
  544.       string_append (result, "volatile");
  545.       break;
  546.     default:
  547.       done = 1;
  548.       break;
  549.     }
  550.     }
  551.  
  552.   if (success)
  553.     switch (**type)
  554.       {
  555.       case '\0':
  556.       case '_':
  557.     break;
  558.       case 'v':
  559.     *type += 1;
  560.     if (non_empty)
  561.       string_append (result, " ");
  562.     string_append (result, "void");
  563.     break;
  564.       case 'x':
  565.     *type += 1;
  566.     if (non_empty)
  567.       string_append (result, " ");
  568.     string_append (result, "long long");
  569.     break;
  570.       case 'l':
  571.     *type += 1;
  572.     if (non_empty)
  573.       string_append (result, " ");
  574.     string_append (result, "long");
  575.     break;
  576.       case 'i':
  577.     *type += 1;
  578.     if (non_empty)
  579.       string_append (result, " ");
  580.     string_append (result, "int");
  581.     break;
  582.       case 's':
  583.     *type += 1;
  584.     if (non_empty)
  585.       string_append (result, " ");
  586.     string_append (result, "short");
  587.     break;
  588.       case 'c':
  589.     *type += 1;
  590.     if (non_empty)
  591.       string_append (result, " ");
  592.     string_append (result, "char");
  593.     break;
  594.       case 'r':
  595.     *type += 1;
  596.     if (non_empty)
  597.       string_append (result, " ");
  598.     string_append (result, "long double");
  599.     break;
  600.       case 'd':
  601.     *type += 1;
  602.     if (non_empty)
  603.       string_append (result, " ");
  604.     string_append (result, "double");
  605.     break;
  606.       case 'f':
  607.     *type += 1;
  608.     if (non_empty)
  609.       string_append (result, " ");
  610.     string_append (result, "float");
  611.     break;
  612.       case 'G':
  613.     *type += 1;
  614.     if (!isdigit (**type))
  615.       {
  616.         success = 0;
  617.         break;
  618.       }
  619.     /* fall through */
  620.       case '0':
  621.       case '1':
  622.       case '2':
  623.       case '3':
  624.       case '4':
  625.       case '5':
  626.       case '6':
  627.       case '7':
  628.       case '8':
  629.       case '9':
  630.     n = 0;
  631.     do
  632.       {
  633.         n *= 10;
  634.         n += **type - '0';
  635.         *type += 1;
  636.       }
  637.     while (isdigit (**type));
  638.     if (strlen (*type) < n)
  639.       {
  640.         success = 0;
  641.         break;
  642.       }
  643.     if (non_empty)
  644.       string_append (result, " ");
  645.     string_appendn (result, *type, n);
  646.     *type += n;
  647.     break;
  648.       default:
  649.     success = 0;
  650.     break;
  651.       }
  652.  
  653.   if (success)
  654.     {
  655.       if (!string_empty (&decl))
  656.     {
  657.       string_append (result, " ");
  658.       string_appends (result, &decl);
  659.     }
  660.       string_delete (&decl);
  661.       return 1;
  662.     }
  663.   else
  664.     {
  665.       string_delete (&decl);
  666.       string_delete (result);
  667.       return 0;
  668.     }
  669. }
  670.  
  671. /* `result' will be initialised in do_type; it will be freed on failure */
  672.  
  673. static int
  674. do_arg (type, result)
  675.      const char **type;
  676.      string *result;
  677. {
  678.   const char *start = *type;
  679.  
  680.   if (!do_type (type, result))
  681.     return 0;
  682.   remember_type (start, *type - start);
  683.   return 1;
  684. }
  685.  
  686. static void
  687. remember_type (start, len)
  688.      const char *start;
  689.      int len;
  690. {
  691.   char *tem;
  692.  
  693.   if (ntypes >= typevec_size)
  694.     {
  695.       if (typevec_size == 0)
  696.     {
  697.       typevec_size = 3;
  698.       typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
  699.     }
  700.       else
  701.     {
  702.       typevec_size *= 2;
  703.       typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
  704.     }
  705.     }
  706.   tem = (char *) xmalloc (len + 1);
  707.   memcpy (tem, start, len);
  708.   tem[len] = '\0';
  709.   typevec[ntypes++] = tem;
  710. }
  711.  
  712. /* `decl' must be already initialised, usually non-empty;
  713.    it won't be freed on failure */
  714.  
  715. static int
  716. do_args (type, decl)
  717.      const char **type;
  718.      string *decl;
  719. {
  720.   string arg;
  721.   int need_comma = 0;
  722.  
  723.   string_append (decl, "(");
  724.  
  725.   while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
  726.     {
  727.       if (**type == 'N')
  728.     {
  729.       int r;
  730.       int t;
  731.       *type += 1;
  732.       if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
  733.         return 0;
  734.       while (--r >= 0)
  735.         {
  736.           const char *tem = typevec[t];
  737.           if (need_comma)
  738.         string_append (decl, ", ");
  739.           if (!do_arg (&tem, &arg))
  740.         return 0;
  741.           string_appends (decl, &arg);
  742.           string_delete (&arg);
  743.           need_comma = 1;
  744.         }
  745.     }
  746.       else
  747.     {
  748.       if (need_comma)
  749.         string_append (decl, ", ");
  750.       if (!do_arg (type, &arg))
  751.         return 0;
  752.       string_appends (decl, &arg);
  753.       string_delete (&arg);
  754.       need_comma = 1;
  755.     }
  756.     }
  757.  
  758.   if (**type == 'v')
  759.     *type += 1;
  760.   else if (**type == 'e')
  761.     {
  762.       *type += 1;
  763.       if (need_comma)
  764.     string_append (decl, ",");
  765.       string_append (decl, "...");
  766.     }
  767.  
  768.   string_append (decl, ")");
  769.   return 1;
  770. }
  771.  
  772. static void
  773. munge_function_name (name)
  774.      string *name;
  775. {
  776.   if (!string_empty (name) && name->p - name->b >= 3 
  777.       && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
  778.     {
  779.       int i;
  780.       /* see if it's an assignment expression */
  781.       if (name->p - name->b >= 10 /* op$assign_ */
  782.       && memcmp (name->b + 3, "assign_", 7) == 0)
  783.     {
  784.       for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
  785.         {
  786.           int len = name->p - name->b - 10;
  787.           if (strlen (optable[i].in) == len
  788.           && memcmp (optable[i].in, name->b + 10, len) == 0)
  789.         {
  790.           string_clear (name);
  791.           string_append (name, "operator");
  792.           string_append (name, optable[i].out);
  793.           string_append (name, "=");
  794.           return;
  795.         }
  796.         }
  797.     }
  798.       else
  799.     {
  800.       for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
  801.         {
  802.           int len = name->p - name->b - 3;
  803.           if (strlen (optable[i].in) == len 
  804.           && memcmp (optable[i].in, name->b + 3, len) == 0)
  805.         {
  806.           string_clear (name);
  807.           string_append (name, "operator");
  808.           string_append (name, optable[i].out);
  809.           return;
  810.         }
  811.         }
  812.     }
  813.       return;
  814.     }
  815.   else if (!string_empty (name) && name->p - name->b >= 5
  816.        && memcmp (name->b, "type$", 5) == 0)
  817.     {
  818.       /* type conversion operator */
  819.       string type;
  820.       const char *tem = name->b + 5;
  821.       if (do_type (&tem, &type))
  822.     {
  823.       string_clear (name);
  824.       string_append (name, "operator ");
  825.       string_appends (name, &type);
  826.       string_delete (&type);
  827.       return;
  828.     }
  829.     }
  830. }
  831.  
  832. /* a mini string-handling package */
  833.  
  834. static void
  835. string_need (s, n)
  836.      string *s;
  837.      int n;
  838. {
  839.   if (s->b == NULL)
  840.     {
  841.       if (n < 32)
  842.     n = 32;
  843.       s->p = s->b = (char *) xmalloc (n);
  844.       s->e = s->b + n;
  845.     }
  846.   else if (s->e - s->p < n)
  847.     {
  848.       int tem = s->p - s->b;
  849.       n += tem;
  850.       n *= 2;
  851.       s->b = (char *) xrealloc (s->b, n);
  852.       s->p = s->b + tem;
  853.       s->e = s->b + n;
  854.     }
  855. }
  856.  
  857. static void
  858. string_delete (s)
  859.      string *s;
  860. {
  861.   if (s->b != NULL)
  862.     {
  863.       free (s->b);
  864.       s->b = s->e = s->p = NULL;
  865.     }
  866. }
  867.  
  868. static void
  869. string_init (s)
  870.      string *s;
  871. {
  872.   s->b = s->p = s->e = NULL;
  873. }
  874.  
  875. static void 
  876. string_clear (s)
  877.      string *s;
  878. {
  879.   s->p = s->b;
  880. }
  881.  
  882. static int
  883. string_empty (s)
  884.      string *s;
  885. {
  886.   return s->b == s->p;
  887. }
  888.  
  889. static void
  890. string_append (p, s)
  891.      string *p;
  892.      const char *s;
  893. {
  894.   int n;
  895.   if (s == NULL || *s == '\0')
  896.     return;
  897.   n = strlen (s);
  898.   string_need (p, n);
  899.   memcpy (p->p, s, n);
  900.   p->p += n;
  901. }
  902.  
  903. static void
  904. string_appends (p, s)
  905.      string *p, *s;
  906. {
  907.   int n;
  908.   if (s->b == s->p)
  909.     return;
  910.   n = s->p - s->b;
  911.   string_need (p, n);
  912.   memcpy (p->p, s->b, n);
  913.   p->p += n;
  914. }
  915.  
  916. static void
  917. string_appendn (p, s, n)
  918.      string *p;
  919.      const char *s;
  920.      int n;
  921. {
  922.   if (n == 0)
  923.     return;
  924.   string_need (p, n);
  925.   memcpy (p->p, s, n);
  926.   p->p += n;
  927. }
  928.  
  929. static void
  930. string_prepend (p, s)
  931.      string *p;
  932.      const char *s;
  933. {
  934.   if (s == NULL || *s == '\0')
  935.     return;
  936.   string_prependn (p, s, strlen (s));
  937. }
  938.  
  939. #if 0
  940. static void
  941. string_prepends (p, s)
  942.      string *p, *s;
  943. {
  944.   if (s->b == s->p)
  945.     return;
  946.   string_prependn (p, s->b, s->p - s->b);
  947. }
  948. #endif
  949.  
  950. static void
  951. string_prependn (p, s, n)
  952.      string *p;
  953.      const char *s;
  954.      int n;
  955. {
  956.   char *q;
  957.  
  958.   if (n == 0)
  959.     return;
  960.   string_need (p, n);
  961.   for (q = p->p - 1; q >= p->b; q--)
  962.     q[n] = q[0];
  963.   memcpy (p->b, s, n);
  964.   p->p += n;
  965. }
  966.